﻿using System;
using StackExchange.Redis;
using System.Collections.Generic;
using System.Threading.Tasks;
using Core.Framework.Model.Common;

namespace Core.Framework.Redis.Queue_Helper
{
    public static class RedisQueueHelper
    {
        static object lockReloadFlag = new object();
        static object lockListPopByLengthFlag = new object();

        static IDatabase GetDateBase(int db, ConnectionMultiplexer conn = null)
        {

            if (db == 15)
            {
                throw new Exception("db num 15 is Exclusive debug");
            }

            // 15号库 专属 DEBUG 环境
            db = CoreStartupHelper.IsDebug ? 15 : db;

            return RedisConnectionHelper.Instance.GetDatabase(db);
        }

        #region RedisProperty

        /// <summary>
        /// 出列
        /// </summary>
        /// <param name="key"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static string ListPop(string key, int db = 2)
        {
            try
            {
                var rrr = GetDateBase(db).ListLeftPopAsync(key);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListLeftPop(key);
            }
        }

        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns>The stack pop.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static string ListStackPop(string key, int db = 2)
        {
            try
            {
                var rrr = GetDateBase(db).ListRightPopAsync(key);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRightPop(key);
            }
        }

        /// <summary>
        /// 入列
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static long ListPush(string key,string value, int db = 2)
        {
            try
            {
                var rrr = GetDateBase(db).ListRightPushAsync(key, value);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRightPush(key, value);
            }
        }

        /// <summary>
        /// 获取列表数量
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static long ListLength(string key,int db = 2)
        {
            try
            {
                var rrr = GetDateBase(db).ListLengthAsync(key);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListLength(key);
            }
        }

        /// <summary>
        /// 删除消息
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static long ListRemove(string key,string value, int db = 2)
        {
            try
            {
                var rrr = GetDateBase(db).ListRemoveAsync(key, value);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRemove(key, value);
            }
        }

        /// <summary>
        /// 获取列表所有数据
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        /// <param name="force">不满足约束</param>
        public static RedisValue[] GetListPopByLength(string key,int start,int stop, int db = 2, bool force = false)
        {

            IRedisHelper iRedis = new RedisHelper(db);

            Task<long> length = null;

            RedisValue[] result = null;

            iRedis.AcquireLock(key, rdb =>
            {
                if (!force)
                    length = rdb.ListLengthAsync(key);

                // 验证是否满足查询数量
                if (length?.Result >= stop || force)
                {
                    result = rdb.ListRange(key, start, stop);
                    rdb.ListTrimAsync(key, stop + 1, -1);
                }

            });

            if (result?.Length > 0)
            {
                return result;
            }
            else
            {
                return new RedisValue[0];
            }

        }


        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="deliverTime">排序字段</param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static bool SortedPush(string key, string value,double deliverTime = 0, int db = 4)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(2019, 8, 19, 0, 0, 0, 0);
            try
            {
                return GetDateBase(db).SortedSetAdd(key, value, ts.TotalMilliseconds + deliverTime);
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static RedisValue[] SortedPop(string key, int db = 4)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(2019, 8, 19, 0, 0, 0, 0);
            RedisValue[] value = null;
            try
            {
                IRedisHelper iRedis = new RedisHelper(db);
                iRedis.AcquireLock(key, rdb =>
                {
                    value = rdb.SortedSetRangeByScore(key, stop: ts.TotalMilliseconds);
                    rdb.SortedSetRemoveRangeByScore(key, start: 0, stop: ts.TotalMilliseconds);
                });
            }
            catch
            {

            }

            return value ?? new RedisValue[0];
        }


        public static bool HashSet(string tableName, string field, string value,int db = 3)
        {
            try
            {
                var ttt = GetDateBase(db).HashSetAsync(tableName, field, value);
                return ttt.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashSet(tableName, field, value);
            }
        }

        public static RedisValue HashGet(string tableName, string field,int db = 3)
        {
            try
            {
                var rrr = GetDateBase(db).HashGetAsync(tableName, field);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashGet(tableName, field);
            }
        }

        public static bool HashDelete(string tableName, string field, int db = 3)
        {
            try
            {
                var rrr = GetDateBase(db).HashDeleteAsync(tableName, field);
                return rrr.Result;
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashDelete(tableName, field);
            }
        }

        #endregion

    }
}
